﻿using System;
using NetMicro.Core.Exceptions;
using NetMicro.Domains.Attributes;

namespace NetMicro.Domains
{
    /// <summary>
    /// 哈希分表策略
    /// </summary>
    public class DefaultHashTableStrategy : ISqlTableStrategy
    {
        /// <summary>
        /// 获取哈希分表策略表
        /// </summary>
        /// <param name="subTableValue"></param>
        /// <param name="tableName"></param>
        /// <param name="attribute"></param>
        /// <returns></returns>
        public string ConvertToTable(object subTableValue, string tableName, Attribute attribute)
        {
            var attr = attribute as HashSubmeterAttribute;
            if (attr.Num <= 0)
            {
                throw new DomainsException("分表数量必须大于零！！");
            }

            long unsign = (long)CRC32Cls.GetCRC32Str(subTableValue.ToString());

            if (unsign < 0) { unsign = unsign * -1; }
            if (unsign > 2147483647)  // sprintf u for 64 & 32 bit
            {
                unsign -= 4294967296;
            }

            if (unsign < 0) { unsign = unsign * -1; }
            string postfix = $"{tableName}_{unsign % attr.Num}";
            return postfix;
        }
    }
    /// <summary>
    /// 
    /// </summary>
    public static class CRC32Cls
    {
        private static ulong[] Crc32Table = null;
        ///生成CRC32码表
        private static void GetCRC32Table()
        {
            ulong Crc;
            Crc32Table = new ulong[256];
            int i, j;
            for (i = 0; i < 256; i++)
            {
                Crc = (ulong)i;
                for (j = 8; j > 0; j--)
                {
                    if ((Crc & 1) == 1)
                        Crc = (Crc >> 1) ^ 0xEDB88320;
                    else
                        Crc >>= 1;
                }
                Crc32Table[i] = Crc;
            }
        }

        ///获取字符串的CRC32校验值
        public static ulong GetCRC32Str(string sInputString)
        {
            //生成码表
            if (Crc32Table == null)
            {
                GetCRC32Table();
            }
            byte[] buffer = System.Text.Encoding.ASCII.GetBytes(sInputString);
            ulong value = 0xffffffff;
            int len = buffer.Length;
            for (int i = 0; i < len; i++)
            {
                value = (value >> 8) ^ Crc32Table[(value & 0xFF) ^ buffer[i]];
            }
            return value ^ 0xffffffff;
        }
    }

}
